package builder

import (
	"context"
	"fmt"
	"os"
	"os/exec"
	"path/filepath"
	"strings"
	"time"

	"xindl/deployer/pkg/errors"
	"xindl/deployer/pkg/logger"
)

// Gradle构建器
type GradleBuilder struct {
	config  *BuildConfig
	log     *logger.Logger
	logFile string
}

// 创建Gradle构建器
func NewGradleBuilder(config *BuildConfig, debug bool) *GradleBuilder {
	return &GradleBuilder{
		config: config,
		log:    logger.New(debug).WithPrefix("Gradle构建器"),
	}
}

// 准备构建环境
func (b *GradleBuilder) Prepare(ctx context.Context, config *BuildConfig) error {
	b.config = config

	// 创建缓存目录
	cacheDir := filepath.Join(config.CacheDir, "gradle")
	if err := os.MkdirAll(cacheDir, 0755); err != nil {
		return errors.WrapSystemError(err, "创建缓存目录失败").
			WithContext("dir", cacheDir)
	}

	// 创建日志目录
	logDir := filepath.Join(config.CacheDir, "logs")
	if err := os.MkdirAll(logDir, 0755); err != nil {
		return errors.WrapSystemError(err, "创建日志目录失败").
			WithContext("dir", logDir)
	}
	b.logFile = filepath.Join(logDir, fmt.Sprintf("build-%s.log", time.Now().Format("20060102-150405")))

	// 生成Gradle配置
	if err := b.generateGradleProperties(); err != nil {
		return errors.WithContext(err, "service", config.ServiceName)
	}

	return nil
}

// 生成Gradle配置文件
func (b *GradleBuilder) generateGradleProperties() error {
	propertiesDir := filepath.Join(b.config.WorkDir, "gradle")
	if err := os.MkdirAll(propertiesDir, 0755); err != nil {
		return errors.WrapSystemError(err, "创建Gradle配置目录失败")
	}

	// 配置文件内容
	content := `
# 镜像源配置
maven.url=https://maven.aliyun.com/repository/public
maven.central.url=https://maven.aliyun.com/repository/central
maven.jcenter.url=https://maven.aliyun.com/repository/public
maven.google.url=https://maven.aliyun.com/repository/google
maven.gradle.url=https://maven.aliyun.com/repository/gradle-plugin

# JDK配置
org.gradle.java.home=/usr/lib/jvm/java-${jdk.version}-openjdk-amd64

# 构建配置
org.gradle.daemon=false
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.jvmargs=-Xmx2048m -XX:MaxPermSize=512m -XX:+HeapDumpOnOutOfMemoryError
`
	content = strings.ReplaceAll(content, "${jdk.version}", b.config.JDKVersion)

	propertiesPath := filepath.Join(propertiesDir, "gradle.properties")
	if err := os.WriteFile(propertiesPath, []byte(content), 0644); err != nil {
		return errors.WrapSystemError(err, "写入Gradle配置失败")
	}

	return nil
}

// 执行构建
func (b *GradleBuilder) Build(ctx context.Context) (*BuildResult, error) {
	startTime := time.Now()

	// 打开日志文件
	logFile, err := os.Create(b.logFile)
	if err != nil {
		return nil, errors.WrapSystemError(err, "创建日志文件失败")
	}
	defer logFile.Close()

	// 构建Gradle命令
	args := []string{
		"build",
		"--no-daemon",
		"--console=plain",
	}

	// 添加构建参数
	if b.config.SkipTests {
		args = append(args, "-x", "test")
	}
	if b.config.Profile != "" {
		args = append(args, "-Pprofile="+b.config.Profile)
	}
	args = append(args, b.config.Args...)

	// 执行Gradle构建
	b.log.Info("开始Gradle构建...")
	cmd := exec.CommandContext(ctx, "./gradlew", args...)
	cmd.Dir = b.config.WorkDir
	cmd.Stdout = logFile
	cmd.Stderr = logFile

	if err := cmd.Run(); err != nil {
		return nil, errors.WrapBuildError(err, "Gradle构建失败").
			WithContext("service", b.config.ServiceName).
			WithContext("logFile", b.logFile)
	}

	// 查找构建产物
	artifactPath, err := b.findArtifact()
	if err != nil {
		return nil, errors.WithContext(err, "service", b.config.ServiceName)
	}

	// 构建Docker镜像
	imageID, err := b.buildDockerImage(ctx, artifactPath)
	if err != nil {
		return nil, errors.WithContext(err, "service", b.config.ServiceName)
	}

	return &BuildResult{
		ArtifactPath: artifactPath,
		ImageID:      imageID,
		Duration:     int64(time.Since(startTime).Seconds()),
		LogFile:      b.logFile,
		CacheUsed:    true,
	}, nil
}

// 查找构建产物
func (b *GradleBuilder) findArtifact() (string, error) {
	buildDir := filepath.Join(b.config.WorkDir, "build", "libs")
	entries, err := os.ReadDir(buildDir)
	if err != nil {
		return "", errors.WrapBuildError(err, "无法访问构建目录")
	}

	for _, entry := range entries {
		if !entry.IsDir() && strings.HasSuffix(entry.Name(), ".jar") {
			return filepath.Join(buildDir, entry.Name()), nil
		}
	}

	return "", errors.NewBuildError("未找到构建产物(JAR包)")
}

// 构建Docker镜像
func (b *GradleBuilder) buildDockerImage(ctx context.Context, artifactPath string) (string, error) {
	// 创建临时Dockerfile
	dockerfileContent := fmt.Sprintf(`
# 使用多阶段构建
FROM %s/openjdk:%s-jre-slim AS runtime
WORKDIR /app
COPY %s app.jar
ENTRYPOINT ["java", "-jar", "app.jar"]
`, b.config.DockerMirror, b.config.JDKVersion, filepath.Base(artifactPath))

	dockerfilePath := filepath.Join(filepath.Dir(artifactPath), "Dockerfile")
	if err := os.WriteFile(dockerfilePath, []byte(dockerfileContent), 0644); err != nil {
		return "", errors.WrapSystemError(err, "创建Dockerfile失败")
	}

	// 构建Docker镜像
	imageName := fmt.Sprintf("%s:%s", b.config.ImageName, b.config.ImageTag)
	args := []string{
		"build",
		"--no-cache",
		"-t", imageName,
		"-f", dockerfilePath,
		filepath.Dir(artifactPath),
	}

	cmd := exec.CommandContext(ctx, "docker", args...)
	output, err := cmd.CombinedOutput()
	if err != nil {
		return "", errors.WrapDockerError(err, fmt.Sprintf("Docker构建失败: %s", string(output)))
	}

	return imageName, nil
}

// 清理构建环境
func (b *GradleBuilder) Clean(ctx context.Context) error {
	// 保留缓存和日志，只清理临时文件
	tempFiles := []string{
		filepath.Join(b.config.WorkDir, "build"),
		filepath.Join(b.config.WorkDir, "Dockerfile"),
	}

	for _, file := range tempFiles {
		if err := os.RemoveAll(file); err != nil {
			b.log.Warn("清理文件失败: %v", err)
		}
	}

	return nil
}

// 获取构建日志路径
func (b *GradleBuilder) LogPath() string {
	return b.logFile
}

// 获取镜像名称
func (b *GradleBuilder) ImageName() string {
	return fmt.Sprintf("%s:%s", b.config.ImageName, b.config.ImageTag)
}
